package com.springmvc;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.springmvc.annotation.Controller;
import com.springmvc.annotation.RequestMapping;
import com.springmvc.annotation.RequestParam;
import com.springmvc.annotation.ResponseBody;
import com.springmvc.context.WebApplicationContext;
import com.springmvc.handler.MyHandler;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MyDispatcherServlet extends HttpServlet {
    private WebApplicationContext webApplicationContext;
    //存放url 和控制器 映射关系的集合
    private List<MyHandler> handlerList = new ArrayList<MyHandler>();

    @Override
    public void init() throws ServletException {
        //1.找到配置文件路径
        String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        //2.创建spring容器
        webApplicationContext = new WebApplicationContext(contextConfigLocation);
        //3.初始化spring容器
        webApplicationContext.refresh();

        //4.初始化请求映射 /user/query
        //找到是哪个Controller，哪个method，哪个参数param
        initHandler();
        System.out.println("handlerList:" + handlerList);


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //5.分发用户请求
        dispatcher(req, resp);
    }

    public void initHandler() {
        /**
         * 从iocMap中找到被Controller标识过的类，
         * 然后再从中找RequestMapping标识的方法
         * 取出value 存入 handlerList
         */
        Map<String, Object> iocMap = webApplicationContext.getIocMap();
        for (Map.Entry<String, Object> map : iocMap.entrySet()) {
            Class<?> aClass = map.getValue().getClass();
            if (aClass.isAnnotationPresent(Controller.class)) {
                //遍历方法找寻requestMapping
                for (Method method : aClass.getMethods()) {
                    if (method.isAnnotationPresent(RequestMapping.class)) {
                        String url = method.getAnnotation(RequestMapping.class).value();
                        handlerList.add(new MyHandler(url, map.getValue(), method));
                    }
                }
            }
        }
    }

    //分发用户请求
    public void dispatcher(HttpServletRequest req, HttpServletResponse resp) {
        /**
         * 根据uri找到对应的handler之后
         * 找到方法对应的参数的Class
         * 给参数赋值
         * 然后执行
         */
        try {


            String requestURI = req.getRequestURI();
            MyHandler myHandler = getMyHandler(requestURI);
            if (myHandler == null) {
                resp.setContentType("text/html");

                resp.getWriter().print("<h1>404...</h1>");

            } else {
                Class<?>[] parameterTypes = myHandler.getMethod().getParameterTypes();
                Object[] params = new Object[parameterTypes.length];

                Map<String, String[]> parameterMap = req.getParameterMap();
                for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
                    String name = entry.getKey();
                    String value = entry.getValue()[0];
                    //判断是否有@RequestMapping注解 的方法
                    int index = this.hasRequestMapping(myHandler.getMethod(), name);
                    if (index != -1) {
                        params[index] = value;
                    } else {
                        //循环遍历方法参数name的集合 找到匹配的然后赋值
                        List<String> allNames = getAllNames(myHandler.getMethod());
                        System.err.println("控制器方法参数名字" + allNames);
                        for (int i = 0; i < allNames.size(); i++) {
                            if (name.equals(allNames.get(i))) {
                                params[i] = value;
                                break;
                            }
                        }
                    }
                    //params[2]=value;
                }

                params[0] = req;
                params[1] = resp;


                //执行方法 得到返回结果
                Object result = myHandler.getMethod().invoke(myHandler.getController(), params);

                if (myHandler.getMethod().isAnnotationPresent(ResponseBody.class)) {
                    //返回值转化为json格式
                    ObjectMapper objectMapper = new ObjectMapper();
                    resp.setContentType("text/html;charset=utf-8");
                    PrintWriter out = resp.getWriter();
                    out.print(objectMapper.writeValueAsString(result));
                    out.flush();
                    out.close();
                } else if ( result instanceof String) {//判断对象类型
                    //跳转视图
                    String valueType=((String) result).split(":")[0];
                    String valuePage=((String) result).split(":")[1];

                    if( ((String) result).contains(":")){
                        if("forward".equals(valueType)){
                            req.getRequestDispatcher(valuePage).forward(req,resp);
                        }else if("redirect".equals(valueType)){
                            //转发
                            resp.sendRedirect(valuePage);
                        }

                    }else{
                        //默认重定向
                        req.getRequestDispatcher(valuePage).forward(req,resp);
                    }
                }


            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    //得到指定Handler
    public MyHandler getMyHandler(String url) {
        if (url != null) {
            for (MyHandler myHandler : handlerList) {
                if (myHandler.getUrl().equals(url)) return myHandler;
            }
        }
        return null;
    }

    //判断是否有@RequestMapping注解
    public int hasRequestMapping(Method method, String name) {
        Parameter[] parameters = method.getParameters();
        for (int i = 0; i < parameters.length; i++) {
            if (parameters[i].isAnnotationPresent(RequestParam.class)) {
                String s = parameters[i].getAnnotation(RequestParam.class).value();
                if (name.equals(s)) {
                    //RequestMapping注解的value和参数key一样就返回参数下标
                    return i;
                }
            }
        }
        return -1;
    }

    //返回方法参数name的集合
    public List<String> getAllNames(Method method) {
        List<String> list = new ArrayList<>();
        Parameter[] parameters = method.getParameters();
        for (Parameter parameter : parameters) {
            list.add(parameter.getName());
        }
        return list;
    }


}
